//=======================================================
//  LVDS Data Output Interface 
//=======================================================
module lvds_output(
	// Internal Control Signals //
	 input 		          		fclka
	,input 		          		fclkb
	,input 		          		vclk
    ,input                      reset_n
    ,input      [11 -1: 0]      weight_in  //2047>1920
    ,input      [11 -1: 0]      height_in  //2047>1080
    ,input                      lvds_vs_pulse
    // From lvds_input module
    ,input                      switch_req
    ,output reg                 switch_ack
    // RGB RAM Interface
    ,output reg [11 -1: 0]      lvds_raddr
    ,input      [48 -1: 0]      lvds_rdata
    // Bicubic output Interface
    ,output reg                 lvds_read_valid
    ,output reg [48 -1: 0]      lvds_rdata_out
    // Display Configure Parameter
    ,input      [11 -1: 0]      SCAL_HS_PRELOGE
    ,input      [11 -1: 0]      SCAL_HS_PULSE  
    ,input      [11 -1: 0]      SCAL_HS_EPILOGE
    ,input      [11 -1: 0]      SCAL_HS_ACTIVE 
    ,input      [12 -1: 0]      SCAL_HS_TOTAL
    ,input      [11 -1: 0]      SCAL_VS_PRELOGE
    ,input      [11 -1: 0]      SCAL_VS_PULSE
    ,input      [11 -1: 0]      SCAL_VS_EPILOGE
    ,input      [11 -1: 0]      SCAL_VS_ACTIVE
    ,input      [12 -1: 0]      SCAL_VS_TOTAL
    // LVDS Output
    ,output wire                TCLK_Aout
    ,output wire                TA_Aout
    ,output wire                TB_Aout
    ,output wire                TC_Aout
    ,output wire                TD_Aout
    ,output wire                TCLK_Bout
    ,output wire                TA_Bout
    ,output wire                TB_Bout
    ,output wire                TC_Bout
    ,output wire                TD_Bout
);

//=======================================================
//  Local parametr 
//=======================================================
localparam      RAM0_BASE = 0;
localparam      RAM1_BASE = 1024;
localparam      BIT = 8;

// localparam HS_PRELOGE = 88;
// localparam HS_PULSE = 44;
// localparam HS_EPILOGE = 148;
// localparam HS_ACTIVE = 1920;
// localparam HS_TOTAL = 2200;
// 
// localparam VS_PRELOGE = 4;
// localparam VS_PULSE = 5;
// localparam VS_EPILOGE = 36;
// localparam VS_ACTIVE = 1080;
// localparam VS_TOTAL = 1125;

// parameter DE = 16;
// parameter HS = 8;

// localparam HS_PRELOGE = 22;
// localparam HS_PULSE = 12;
// localparam HS_EPILOGE = 38;
// //localparam HS_ACTIVE = 480;
// localparam HS_ACTIVE = DE;
// localparam HS_TOTAL = HS_PRELOGE + HS_PULSE + HS_EPILOGE + HS_ACTIVE;
// 
// localparam VS_PRELOGE = 2;
// localparam VS_PULSE = 1;
// localparam VS_EPILOGE = 9;
// //localparam VS_ACTIVE = 270;
// localparam VS_ACTIVE = HS;
// localparam VS_TOTAL = VS_PRELOGE + VS_PULSE + VS_EPILOGE + VS_ACTIVE;

//=======================================================
//  REG/WIRE declarations
//=======================================================
reg                     switch_req_d;
//! reg                     switch_req_d1;
//! reg                     switch_req_d2;
//! reg                     switch_req_d3;

reg     [11 -1: 0]      linePix_addr;
reg     [11 -1: 0]      linePix_count;
reg     [11 -1: 0]      line_count; //2047
reg     [12 -1: 0]      base_addr; //4095

reg     [11 -1: 0]      weight;  //2047>1920
reg     [11 -1: 0]      height;  //2047>1080

reg                     read_enable;
reg                     read_address_en;
reg                     read_enable_d1;
reg                     read_data_en;

// RGB CONTROL //
reg                     de;
reg                     hs;
reg                     vs;
reg                     de_r;
// RGB DATA //
reg     [8 -1: 0]       pr;
reg     [8 -1: 0]       pg;
reg     [8 -1: 0]       pb;
//
reg                     start;
reg     [32 -1: 0]      pixel;
//reg     [32 -1: 0]      line_count;
reg     [32 -1: 0]      line;
reg     [32 -1: 0]      frame;
// LVDS Signals
wire    [8 -1: 0]       pr_da;
wire    [8 -1: 0]       pg_da;
wire    [8 -1: 0]       pb_da;
wire    [8 -1: 0]       pr_db;
wire    [8 -1: 0]       pg_db;
wire    [8 -1: 0]       pb_db;
wire                    RST_Tx;
wire    [7 -1: 0]       TA_Ain;
wire    [7 -1: 0]       TB_Ain;
wire    [7 -1: 0]       TC_Ain;
wire    [7 -1: 0]       TD_Ain;
wire    [7 -1: 0]       TA_Bin;
wire    [7 -1: 0]       TB_Bin;
wire    [7 -1: 0]       TC_Bin;
wire    [7 -1: 0]       TD_Bin;

wire    [7 -1: 0]       TA_Ain_buf;
wire    [7 -1: 0]       TB_Ain_buf;
wire    [7 -1: 0]       TC_Ain_buf;
wire    [7 -1: 0]       TD_Ain_buf;
wire    [7 -1: 0]       TA_Bin_buf;
wire    [7 -1: 0]       TB_Bin_buf;
wire    [7 -1: 0]       TC_Bin_buf;
wire    [7 -1: 0]       TD_Bin_buf;

wire sclka;
wire sclkb;
wire ae_a;
wire ae_b;

//=======================================================
//  Structural coding
//=======================================================
// register the frame height and weight at the vs_posPluse.
always@(posedge vclk or negedge reset_n)
begin
  if (!reset_n) begin
    weight <= 0;
    height <= 0;
//  end else if(vs_posPluse) begin
  end else begin
    weight <= weight_in;
    height <= height_in;
  end
end

//-- generate switch_ack signal
always@(posedge vclk or negedge reset_n)
begin
  if (!reset_n) begin
    switch_req_d  <= 0;
//!    switch_req_d1 <= 0;
//!    switch_req_d2 <= 0;
//!    switch_req_d3 <= 0;
  end else begin
    switch_req_d  <= switch_req;
//!    switch_req_d1 <= switch_req_d;
//!    switch_req_d2 <= switch_req_d1;
//!    switch_req_d3 <= switch_req_d2;
  end
end

always@(posedge vclk or negedge reset_n)
begin
  if (!reset_n) begin
    switch_ack <= 0;
//!  end else if (switch_req_d2 & (!switch_req_d3)) begin
  end else if (read_enable) begin
    switch_ack <= 0;
  end else if (switch_req_d) begin
    switch_ack <= 1;
  end
end

//assign switch_pulse = switch_req_d & (!switch_req_d1);

//-- generate each frame start level
always@(posedge vclk or negedge reset_n)
begin
  if (!reset_n) begin
    start <= 0;
  end else if (lvds_vs_pulse) begin
    start <= 1;
  end else if ((line == SCAL_VS_TOTAL-1) && (pixel == (SCAL_HS_TOTAL>>1) -1))begin
    start <= 0;
  end
end

//-- counter the pix each line.
always@(posedge vclk or negedge reset_n)
begin
  if(!reset_n) begin
    pixel <= 0;
  end else if (pixel == (SCAL_HS_TOTAL>>1) -1) begin
    pixel <= 0;
  end else if (start) begin
    pixel <= pixel + 1;
  end
end

always@(posedge vclk or negedge reset_n)
begin
  if(!reset_n) begin
//    line <= SCAL_VS_PRELOGE -1;
    line <= 0;
  end else if ((line == SCAL_VS_TOTAL-1) && (pixel == (SCAL_HS_TOTAL>>1) -1))begin
    line <= 0;
  end else if (pixel == (SCAL_HS_TOTAL>>1) -1) begin
    line <= line + 1;
  end
end

always@(posedge vclk or negedge reset_n)
begin
  if(!reset_n) begin
    frame <= 0;
  end else if ((line == SCAL_VS_TOTAL-1) && (pixel == (SCAL_HS_TOTAL>>1) -1))begin
    frame <= frame + 1;
  end
end

//-- vs output low
always@(posedge vclk or negedge reset_n)
begin
  if(!reset_n) begin
    vs <= 1;
  end else if (start) begin
    if ((line < SCAL_VS_PULSE -1)
                && (pixel == (SCAL_HS_TOTAL>>1) -1)) begin
      vs <= 0;
    end else if (((line >= SCAL_VS_PULSE -1) && (line < (SCAL_VS_TOTAL -1)))
                && (pixel == (SCAL_HS_TOTAL>>1) -1)) begin
      vs <= 1;
    end
  end else begin
    vs <= 1; //default set high
  end
end

//!!begin
//!!  if(!reset_n) begin
//!!    vs <= 1;
//!!  end else if (line < SCAL_VS_PRELOGE -1) begin
//!!    vs <= 1;
//!!  end else if ((line >= SCAL_VS_PRELOGE -1) && (line < (SCAL_VS_PRELOGE + SCAL_VS_PULSE -1))) begin
//!!    vs <= 0;
//!!  end else if ((line >= SCAL_VS_PRELOGE + SCAL_VS_PULSE -1) && (line < (SCAL_VS_TOTAL -1))) begin
//!!    vs <= 1;
//!!  end
//!!end
//! begin
//!   if(!reset_n) begin
//!     vs <= 1;
//!   end else if ((line < (SCAL_VS_EPILOGE + SCAL_VS_ACTIVE + SCAL_VS_PRELOGE -1)) || (line >= (SCAL_VS_TOTAL -1))) begin
//!     vs <= 1;
//!   end else if ((line >= (SCAL_VS_EPILOGE + SCAL_VS_ACTIVE + SCAL_VS_PRELOGE -1)) && (line < (SCAL_VS_TOTAL -1))) begin
//!     vs <= 0;
//!   end
//! end

//-- hs output low
always@(posedge vclk or negedge reset_n)
begin
  if(!reset_n) begin
    hs <= 1;
  end else if ((pixel < (SCAL_HS_PRELOGE>>1) -1) || (pixel >= ((SCAL_HS_TOTAL>>1) -1)))begin
    hs <= 1;
  end else if ((pixel >= (SCAL_HS_PRELOGE>>1) -1) && (pixel < ((SCAL_HS_PRELOGE + SCAL_HS_PULSE)>>1) -1)) begin
    hs <= 0;
  end else if ((pixel >= ((SCAL_HS_PRELOGE + SCAL_HS_PULSE>>1) -1)) && (pixel < ((SCAL_HS_TOTAL>>1) -1))) begin
    hs <= 1;
  end
end
//! begin
//!   if(!reset_n) begin
//!     hs <= 1;
//!   end else if ((pixel < (SCAL_HS_PRELOGE>>1) -1) || (pixel >= ((SCAL_HS_TOTAL>>1) -1)))begin
//!     hs <= 1;
//!   end else if ((pixel >= (SCAL_HS_PRELOGE>>1) -1) && (pixel < (((SCAL_HS_PRELOGE + SCAL_HS_PULSE)>>1) -1))) begin
//!     hs <= 0;
//!   end else if ((pixel >= (((SCAL_HS_PRELOGE + SCAL_HS_PULSE)>>1) -1)) && (pixel < ((SCAL_HS_TOTAL>>1) -1))) begin
//!     hs <= 1;
//!   end
//! end

//-- de output high
always@(posedge vclk or negedge reset_n)
begin
  if(!reset_n) begin
    de <= 0;
  end else if ((pixel < (((SCAL_HS_PRELOGE + SCAL_HS_PULSE + SCAL_HS_EPILOGE)>>1) -1)) || (pixel >= ((SCAL_HS_TOTAL>>1) -1))) begin
    de <= 0;
  end else if (((line >= (SCAL_VS_PULSE + SCAL_VS_EPILOGE -1)) && (line < (SCAL_VS_PULSE + SCAL_VS_EPILOGE + SCAL_VS_ACTIVE -1))) 
            && ((pixel >= (((SCAL_HS_PRELOGE + SCAL_HS_PULSE + SCAL_HS_EPILOGE)>>1) -1)) && (pixel < ((SCAL_HS_TOTAL>>1) -1))))begin
    de <= 1;
  end
end
//!!begin
//!!  if(!reset_n) begin
//!!    de <= 0;
//!!  end else if ((pixel < (((SCAL_HS_PRELOGE + SCAL_HS_PULSE + SCAL_HS_EPILOGE)>>1) -1)) || (pixel >= ((SCAL_HS_TOTAL>>1) -1))) begin
//!!    de <= 0;
//!!  end else if (((line >= (SCAL_VS_PRELOGE + SCAL_VS_PULSE + SCAL_VS_EPILOGE -1)) && (line < (SCAL_VS_TOTAL -1))) 
//!!            && ((pixel >= (((SCAL_HS_PRELOGE + SCAL_HS_PULSE + SCAL_HS_EPILOGE)>>1) -1)) && (pixel < ((SCAL_HS_TOTAL>>1) -1))))begin
//!!    de <= 1;
//!!  end
//!!end
//! begin
//!   if(!reset_n) begin
//!     de <= 0;
//!   end else if ((pixel < (((SCAL_HS_PRELOGE + SCAL_HS_PULSE + SCAL_HS_EPILOGE)>>1) -1)) || (pixel >= ((SCAL_HS_TOTAL>>1) -1))) begin
//!     de <= 0;
//!   end else if (((line >= (SCAL_VS_EPILOGE -1)) && (line < (SCAL_VS_EPILOGE + SCAL_VS_ACTIVE -1))) 
//!             && ((pixel >= (((SCAL_HS_PRELOGE + SCAL_HS_PULSE + SCAL_HS_EPILOGE)>>1) -1)) && (pixel < ((SCAL_HS_TOTAL>>1) -1))))begin
//!     de <= 1;
//!   end
//! end

always@(posedge vclk or negedge reset_n)
begin
  if(!reset_n) begin
    de_r <= 0;
  end else begin
    de_r <= de;
  end
end
assign de_negPulse = (!de) & de_r;

//-- get data
//-- From the read_enable to get the lvds data back need 4 cycles.
always@(posedge vclk or negedge reset_n)
begin
  if (!reset_n) begin
    read_enable <= 0;
  end else if (linePix_addr == ((weight>>1) -1)) begin
    read_enable <= 0;
//!  end else if (((line >= (SCAL_VS_EPILOGE -1)) && (line < (SCAL_VS_EPILOGE + SCAL_VS_ACTIVE -1))) 
//!            && ((pixel >= (((SCAL_HS_PRELOGE + SCAL_HS_PULSE + SCAL_HS_EPILOGE)>>1) -5)) && (pixel < ((SCAL_HS_TOTAL>>1) -5))))begin
//!!  end else if (((line >= (SCAL_VS_PRELOGE + SCAL_VS_PULSE + SCAL_VS_EPILOGE -1)) && (line < (SCAL_VS_TOTAL -1))) 
  end else if (((line >= (SCAL_VS_PULSE + SCAL_VS_EPILOGE -1)) && (line < (SCAL_VS_PULSE + SCAL_VS_EPILOGE + SCAL_VS_ACTIVE -1))) 
            && ((pixel >= (((SCAL_HS_PRELOGE + SCAL_HS_PULSE + SCAL_HS_EPILOGE)>>1) -5)) && (pixel < ((SCAL_HS_TOTAL>>1) -5))))begin
    read_enable <= 1;
  end
end

always@(posedge vclk or negedge reset_n)
begin
  if (!reset_n) begin
    read_address_en<= 0;
    read_enable_d1 <= 0;
    read_data_en   <= 0;
  end else begin
    read_address_en<= read_enable;
    read_enable_d1 <= read_address_en;
    read_data_en   <= read_enable_d1;
  end
end

//-- counter the input RGB data number
always@(posedge vclk or negedge reset_n)
begin
  if (!reset_n) begin
    linePix_addr <= 0;
  end else if (linePix_addr == ((weight>>1) -1)) begin
    linePix_addr <= 0;
  end else if (read_enable) begin
    linePix_addr <= linePix_addr + 1'b1;
  end
end

always@(posedge vclk or negedge reset_n)
begin
  if(!reset_n) begin
    line_count <= 0;
  end else if (line_count == (height -1) && de_negPulse) begin
    line_count <= 0;
  end else if (de_negPulse) begin
    line_count <= line_count + 1'b1;
  end
end

//-- generete the base_addr
always@(posedge vclk or negedge reset_n)
begin
  if (!reset_n) begin
    base_addr <= RAM0_BASE;
  end else if (line_count[0] == 1'b0) begin
    base_addr <= RAM0_BASE;
  end else if (line_count[0] == 1'b1) begin
    base_addr <= RAM1_BASE;
  end
end

//-- generate the rgb ram interface
always@(posedge vclk or negedge reset_n)
begin
  if (!reset_n) begin
    lvds_raddr <= 0;
  end else if (read_address_en) begin
    lvds_raddr  <= (base_addr + linePix_addr);
  end else begin
    lvds_raddr <= base_addr;
  end
end

always@(posedge vclk or negedge reset_n)
begin
  if (!reset_n) begin
    lvds_rdata_out <= 0;
    lvds_read_valid <= 0;
  end else if (read_data_en) begin
    lvds_rdata_out <= lvds_rdata;
    lvds_read_valid <= 1;
  end else begin
    lvds_rdata_out <= 0;
    lvds_read_valid <= 0;
  end
end

always@(posedge vclk or negedge reset_n)
begin
  if (!reset_n) begin
    linePix_count <= 0;
  end else if (linePix_count == ((weight>>1) -1)) begin
    linePix_count <= 0;
  end else if (lvds_read_valid) begin
    linePix_count <= linePix_count + 1;
  end else begin
    linePix_count <= 0;
  end
end

assign pr_db = lvds_rdata_out[6*BIT -1: BIT*5];
assign pg_db = lvds_rdata_out[5*BIT -1: BIT*4];
assign pb_db = lvds_rdata_out[4*BIT -1: BIT*3];
assign pr_da = lvds_rdata_out[3*BIT -1: BIT*2];
assign pg_da = lvds_rdata_out[2*BIT -1: BIT];
assign pb_da = lvds_rdata_out[1*BIT -1: 0];

assign CLK_Tx = vclk;
assign RST_Tx = !reset_n;
assign TA_Ain = {pg_da[2], pr_da[7:2]};
assign TB_Ain = {pb_da[3:2], pg_da[7:3]};
assign TC_Ain = {de, vs, hs, pb_da[7:4]};
assign TD_Ain = {1'b1, pb_da[1:0], pg_da[1:0], pr_da[1:0]};

assign TA_Bin = {pg_db[2], pr_db[7:2]};
assign TB_Bin = {pb_db[3:2], pg_db[7:3]};
assign TC_Bin = {de, vs, hs, pb_db[7:4]};
assign TD_Bin = {1'b1, pb_db[1:0], pg_db[1:0], pr_db[1:0]};


reg        stop1, stop2, stop3, stop;        // pipe delay
//--------------------------------------------------------------------
//-- divider sync signal generation
//--------------------------------------------------------------------
//always @(posedge fclka or negedge reset_n)
always @(posedge vclk or negedge reset_n)
begin
   if (!reset_n) begin
      stop1    <= 1'b1;
      stop2    <= 1'b1;
      stop3    <= 1'b1;
      stop     <= 1'b1;
   end else begin
      stop1    <= 1'b0;
      stop2    <= stop1;
      stop3    <= stop2;
      stop     <= stop3;
   end
end

fifo_28b fifoa(.Data    ({TA_Ain,TB_Ain,TC_Ain,TD_Ain}), 
               .WrClock (vclk), 
               .RdClock (sclka), 
               .WrEn    (1'b1), 
               .RdEn    (~ae_a), 
               .Reset   (RST_Tx), 
               .RPReset (RST_Tx), 
               .Q       ({TA_Ain_buf,TB_Ain_buf,TC_Ain_buf,TD_Ain_buf}),  
               .Empty   (), 
               .Full    (), 
               .AlmostEmpty (ae_a), 
               .AlmostFull ());
    
LVDS_7_to_1_TX U_LVDS_7to1_TXA (
       .RST_Tx(RST_Tx)

      ,.T0_in(TA_Ain_buf)
      ,.T1_in(TB_Ain_buf)
      ,.T2_in(TC_Ain_buf)
      ,.T3_in(TD_Ain_buf)

      ,.eclk(fclka)
      ,.clk_s(vclk)
      ,.stop(stop)
      ,.sclk(sclka)
      ,.TCLK_out(TCLK_Aout)
      ,.T0_out(TA_Aout)
      ,.T1_out(TB_Aout)
      ,.T2_out(TC_Aout)
      ,.T3_out(TD_Aout)
);

fifo_28b fifob(.Data    ({TA_Bin,TB_Bin,TC_Bin,TD_Bin}), 
               .WrClock (vclk), 
               .RdClock (sclkb), 
               .WrEn    (1'b1), 
               .RdEn    (~ae_b), 
               .Reset   (RST_Tx), 
               .RPReset (RST_Tx), 
               .Q       ({TA_Bin_buf,TB_Bin_buf,TC_Bin_buf,TD_Bin_buf}),  
               .Empty   (), 
               .Full    (), 
               .AlmostEmpty (ae_b), 
               .AlmostFull ());
               
LVDS_7_to_1_TX U_LVDS_7to1_TXB (
       .RST_Tx(RST_Tx)

      ,.T0_in(TA_Bin_buf)
      ,.T1_in(TB_Bin_buf)
      ,.T2_in(TC_Bin_buf)
      ,.T3_in(TD_Bin_buf)

      ,.eclk(fclkb)
      ,.clk_s(vclk)
      ,.stop(stop)
      ,.sclk(sclkb)
      ,.TCLK_out(TCLK_Bout)
      ,.T0_out(TA_Bout)
      ,.T1_out(TB_Bout)
      ,.T2_out(TC_Bout)
      ,.T3_out(TD_Bout)
);



endmodule

